/**
 * @file 	 dyp.c
 * @brief
 * @author 	 wenbo
 * @version  1.0
 * @date 	 2022-02-11
 *
 * @copyright Copyright (c) 2022  YGL
 *
 */

#include "dyp_485.h"
#include "modbus_485.h"
#include "stdlib.h"
#include "string.h"

#define _ABS(n)  (n < 0 ? (-n) : (n))
#define IS_VALID_PIN(id)    (id > 0 ? (true) : (false))
#define IS_DYP_CHECK_OK(devId) (((devId) < g_dyp_listLen) && (g_dyp_list) && (g_dyp_list[(devId)].isInitOk))


 //不同的项目需要在应用层配置好Type_dyp_Def列表然后传入初始化
 /**************************************************************/
static uint8_t g_dyp_listLen = 0;
static Type_dyp_Def* g_dyp_list = NULL;
/**************************************************************/


static int xp_dyp_debug(char* type, char* fun, char* param);

void xp_dyp_show(int devId);
bool _xp_dyp_update_all(Type_dyp_Def* const handle);
bool _xp_dyp_update_single(Type_dyp_Def* const handle, int probeId);

int xp_dyp_write_reginster(Type_dyp_Def* const handler, uint16_t addr, uint16_t* data, uint8_t len);
int xp_dyp_read_reginster(Type_dyp_Def* const handler, uint16_t addr, uint16_t read_len, uint8_t* rec_data, uint8_t* rec_len);

// Type_dyp_Def dyp[] = {
//     [0] = {
//         .com = {
//             .port = 1,
//             .slave_id = 1,
//             .speed = 9600,
//         },
//     },
// };


// dyp初始化
bool xp_dyp_init(Type_dyp_Def* const pList, uint8_t listLen)
{
    int ret = 0;

    if (NULL != pList && 0 != listLen) {

        g_dyp_list = pList;
        g_dyp_listLen = listLen;

        for (uint8_t i = 0; i < g_dyp_listLen; i++) {

            g_dyp_list[i].isInitOk = false;

            ret = xp_modbus_init(g_dyp_list[i].com.port, g_dyp_list[i].com.speed, MB_PAR_NONE, 100);
            MB_state *state = xp_get_modbus_port(g_dyp_list[i].com.port);
            state->mb_handler->respond_timeout = 130;   // 超声波采集板每个探头发送读取命令后的回应延迟为110ms
            if (0 != ret) {
                println("dyp <id:%d> modbus init fail ! ret = %d", g_dyp_list[i].com.slave_id, ret);
                return false;
            }
            else {
                if (_xp_dyp_update_all(&g_dyp_list[i])) {
                    g_dyp_list[i].isInitOk = true;
                    for (size_t j = 0; j < SENS_NUMS; j++) {
                        printf("DYP devId %d-%d val is %d\r\n", i, j, g_dyp_list[j].sensdatas[i]);
                    }
                }else{
                    printf("DYP devId %d update failed\r\n", i);
                }
            }
        }

        xp_cli_debug_add(xp_dyp_debug);
        return true;

    }
    else {
        return false;
    }
}
// dyp去初始化
bool xp_dyp_Deinit(void)
{
    bool ret = true;
    for (int i = 0; i < g_dyp_listLen; i++) {
        g_dyp_list[i].isInitOk = false;
    }
    return ret;
}
// dyp 读取指定探头数据
bool _xp_dyp_update_single(Type_dyp_Def* const handle, int probeId)
{
    int ret = xp_dyp_read_reginster(handle, ADDR_SENS_1 + probeId, 1, handle->com.rec_data, &handle->com.rec_len);
    if (0 == ret) {
        handle->sensdatas[probeId] = (handle->com.rec_data[0] << 8) | handle->com.rec_data[1];
        return true;
    }
    return false;
}
// dyp 读取所有探头数据
bool _xp_dyp_update_all(Type_dyp_Def* const handle)
{
    int ret = xp_dyp_read_reginster(handle, ADDR_SENS_1, SENS_NUMS, handle->com.rec_data, &handle->com.rec_len);
    if (0 == ret) {
        for (size_t i = 0; i < SENS_NUMS; i++) {
            handle->sensdatas[i] = (handle->com.rec_data[i * 2] << 8) | handle->com.rec_data[i * 2 + 1];
        }
        return true;
    }
    return false;
}
int xp_dyp_write_reginster(Type_dyp_Def* const handler, uint16_t addr, uint16_t* data, uint8_t len)
{
    int sta = 0;
    MB_data modbus;
    uint8_t try_times = 3;

    modbus.slave_id = handler->com.slave_id;
    modbus.mb_fun = mb_single_w;
    modbus.start_addr = addr;
    modbus.wBuf = data;
    modbus.rwLen = len;
    modbus.resBuf = handler->com.rec_data;
    modbus.resLen = &handler->com.rec_len;
    while (try_times--) {
        if (0 == xp_modbus_ask(handler->com.port, &modbus)) return 0;
    }

    return -1;
}

int xp_dyp_read_reginster(Type_dyp_Def* const handler, uint16_t addr, uint16_t read_len, uint8_t* rec_data, uint8_t* rec_len)
{
    int sta = 0;
    MB_data modbus;
    uint8_t try_times = 3;

    modbus.slave_id = handler->com.slave_id;
    modbus.mb_fun = mb_hold_r;
    modbus.start_addr = addr;
    modbus.rwLen = read_len;
    modbus.resBuf = rec_data;
    modbus.resLen = rec_len;
    while (try_times--) {
        if (0 == xp_modbus_ask(handler->com.port, &modbus)) return 0;
    }
    println("dyp read fail !!!");
    return -1;
}


//外部接口
/********************************************************************************************/
bool xp_dyp_get_all_data(int devId, uint16_t pResult[])
{
    if (IS_DYP_CHECK_OK(devId) && pResult) {
        if (_xp_dyp_update_all(&g_dyp_list[devId])) {
            for (size_t i = 0; i < SENS_NUMS; i++) {
                pResult[i] = g_dyp_list[devId].sensdatas[i];
            }
            return true;
        }
        else {
            return false;
        }
    }
}
bool xp_dyp_get_single_data(int devId, int probeId, uint16_t *pResult)
{
    if (IS_DYP_CHECK_OK(devId) && pResult) {
        if (_xp_dyp_update_single(&g_dyp_list[devId], probeId)) {
            *pResult = g_dyp_list[devId].sensdatas[probeId];
            return true;
        }
        else {
            return false;
        }
    }
    return false;
}
void xp_dyp_show(int devId)
{
    if (IS_DYP_CHECK_OK(devId)) {
        if (_xp_dyp_update_all(&g_dyp_list[devId])) {
            for (size_t i = 0; i < SENS_NUMS; i++) {
                printf("DYP devId %d-%d val is %d\r\n", devId, i, g_dyp_list[devId].sensdatas[i]);
            }        
        }else{
            printf("DYP devId %d update failed\r\n", devId);
        }
    }else{
        printf("DYP devId %d is not init\r\n", devId);
    }
}

//调试接口
/********************************************************************************************/
static int xp_dyp_debug(char* type, char* fun, char* param)
{
    //本调试接口仅支持 "dyp_" 起始的命令
    if (NULL == strstr(type, "dyp_")) {
        return 0;
    }
    else {
        type += strlen("dyp_");
    }
    //xp dyp_show  输出相关信息
    if (strcasecmp(type, "show") == 0) {
        xp_dyp_show(atoi(fun));
    }
    else {
        return 0;
    }
    return 1;
}